package com.dks.repository.impl;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import com.aliyuncs.dysmsapi.model.v20170525.QuerySendDetailsResponse;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
import com.aliyuncs.exceptions.ClientException;
import com.dks.businessUtil.RewardUtil;
import com.dks.dto.UserDto;
import com.dks.dto.UserInfoDto;
import com.dks.exception.BaseException;
import com.dks.mapper.ParentMapper;
import com.dks.mapper.UsersMapper;
import com.dks.mapper.WechatUserInfoMapper;
import com.dks.models.AliyunSendSmsLogs;
import com.dks.models.Users;
import com.dks.models.WechatUserInfo;
import com.dks.repository.IUsersRepository;
import com.dks.result.Result;
import com.dks.result.ResultInfo;
import com.dks.result.ResultModel;
import com.dks.util.ALiYunSmsUtils;
import com.dks.util.Commond;
import com.dks.util.PageInfo;
import com.dks.util.QSUnirest;
import com.dks.vo.ParentVo;
import com.dks.vo.TeacherVo;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;

import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

@Repository
public class UsersRepository implements IUsersRepository {

    private final org.slf4j.Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    private UsersMapper usersMapper;

    @Autowired
    private ParentMapper parentMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private WechatUserInfoMapper wechatUserInfoMapper;

    @Autowired
    private AliyunSendSmsLogsRepository aliyunSendSmsLogsRepository;

    @Override
    public Integer insert(Users users) {
        return usersMapper.insert(users);
    }

    @Override
    public Integer update(Users users) {
        return usersMapper.update(users);
    }

    @Override
    public Integer delete(Integer id) {
        return usersMapper.delete(id);
    }

    @Override
    public ResultModel<Object> select(Integer id) {

        int pageNum = 1;
        int pageSize = 10;
        if (String.valueOf(pageNum) != null) {
            pageNum = pageNum;
        }
        if (String.valueOf(pageSize) != null) {
            pageSize = pageSize;
        }

        Map<String, Object> map = new HashMap<>();
        map.put("id", id);
        Page p = PageHelper.startPage(pageNum, pageSize);
        List<Users> usersList = usersMapper.getByMapList(map);
        PageInfo<Users> pageInfo = new PageInfo<>(pageNum, pageSize, p.getTotal(), p.getPages(), usersList);

        return Result.makeResult(ResultInfo.SUCCESS, pageInfo);
    }

    @Override
    public Integer cntByMap(Map<String, Object> map) {
        return usersMapper.cntByMap(map);
    }

    @Override
    public List<Integer> getByMap(Map<String, Object> map) {
        return usersMapper.getByMap(map);
    }

    @Override
    public List<Users> getByMapList(Map<String, Object> map) {
        return usersMapper.getByMapList(map);
    }

    @Override
    public Integer updateByCode(Users users) {
        return usersMapper.updateByCode(users);
    }

    @Override
    public Users selectByBfCode(String bfCode) {
        return usersMapper.selectByBfCode(bfCode);
    }

    /**
     * @Author: Ah Nan
     * @Description:获取用户手机号
     * @Param: tel
     * @return: ResultModel
     * @Date: 2020/4/19
     */
    @Override
    public ResultModel<Object> getTelCode(String tel) throws BaseException, ClientException {


        ALiYunSmsUtils aLiYunSmsUtils = new ALiYunSmsUtils();
        SendSmsResponse response = new SendSmsResponse();
        int code;
        try {
            code = (int) ((Math.random() * 9 + 1) * 100000);
            response = aLiYunSmsUtils.sendSms(tel, "SMS_168345607", "{\"code\":\"" + code + "\"}", "0");
        } catch (Exception e) {
            throw new BaseException(ResultInfo.ERR_SEND_SMS);
        }
        //查明细
        if (response.getCode() != null && response.getCode().equals("OK")) {
            QuerySendDetailsResponse querySendDetailsResponse =
                    aLiYunSmsUtils.querySendDetails(response.getBizId(), tel, 10, 1);
            //将验证码记录到redis 5分钟过时
            redisTemplate.opsForValue().set(Commond.REDIS_KEY_PHONE_IDENTIFY_CODE + tel, String.valueOf(code), 5, TimeUnit.MINUTES);

            for (QuerySendDetailsResponse.SmsSendDetailDTO smsSendDetailDTO
                    : querySendDetailsResponse.getSmsSendDetailDTOs()) {
                //将验证码插入到aliyun_send_sms_logs表中
                AliyunSendSmsLogs aliyunSendSmsLogs = new AliyunSendSmsLogs();
                aliyunSendSmsLogs.setPhoneNumber(smsSendDetailDTO.getPhoneNum());
                aliyunSendSmsLogs.setTemplateCode("SMS_168345607");
                aliyunSendSmsLogs.setTemplateParam("{\"code\":\"" + code + "\"}");
                aliyunSendSmsLogs.setOutid(smsSendDetailDTO.getOutId());
                aliyunSendSmsLogs.setCode(String.valueOf(code));
                aliyunSendSmsLogs.setMessage(response.getMessage());
                aliyunSendSmsLogs.setRequestId(response.getRequestId());
                aliyunSendSmsLogs.setBizId(response.getBizId());
                aliyunSendSmsLogsRepository.insert(aliyunSendSmsLogs);
            }
        } else {
            //触发流控
            return Result.makeResult(ResultInfo.ERR_BUSINESS_LIMIT_CONTROL, tel);
        }

        return Result.makeResult(ResultInfo.SUCCESS, tel);
    }

    /**
     * @Author: Ah Nan
     * @Description: 手机号验证码登录
     * @Date: 10:42 2020/4/20
     * @Modificd By:
     * @Param: userType 用户类型 0 家长、1 老师
     * @return:
     * @throw: 请描述异常信息
     */
    @Override
    @Transactional
    public ResultModel<Object> appLogin(String tel, String code, String wechatCode) {

        Integer userType = 0;

        //校验验证码是否和传过来的一致
        Object obj = redisTemplate.opsForValue().get(Commond.REDIS_KEY_PHONE_IDENTIFY_CODE + tel);
        if (null == obj || !code.equals(obj)) {
            return Result.makeResult(ResultInfo.EXCEPTION, "验证码已失效");
        }

        String tokenStr = "";
        //校验code
        try {
            tokenStr = QSUnirest.unirestGetBase("https://api.weixin.qq.com/sns/jscode2session?appid=" + Commond.PARENT_APP_ID + "&secret=" + Commond.PARENT_APP_SECRET + "&js_code=" + wechatCode + "&grant_type=authorization_code");
        } catch (Exception e) {
            e.printStackTrace();
            logger.info("登录接口校验code异常：  " + tel);
        }

        final com.alibaba.fastjson.JSONObject tokenJo = com.alibaba.fastjson.JSONObject.parseObject(tokenStr);
        final String access_token = tokenJo.getString("access_token");
        final String openid = tokenJo.getString("openid");

        //根据openid查询微信用户信息
        String nickname = "";
        final WechatUserInfo wechatUserInfo = wechatUserInfoMapper.selectByOpenId(openid);

        Map map = new HashMap();
        map.put("loginName", tel);
        map.put("userType", userType);
        map.put("recStatus", 0);
        List<Users> usersList = usersMapper.getByMapList(map);

        //家长端没信息 插入
        if (usersList!=null&&usersList.isEmpty()) {
            //为空代表表中没有该用户,此时直接注册
            Users users = new Users();
            Date date = new Date();
            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
            users.setLoginName(tel);
            users.setUserType(userType);
            users.setNickname("家长用户" + sdf.format(date) + String.valueOf((int) (Math.random() * (9999 - 1000 + 1)) + 1000));
            users.setProfilePhotoUrl("http://img.qiestar.com/%E5%A4%B4%E5%83%8F.png");
            int rowIns = usersMapper.insert(users);

            //插入家长信息
            com.dks.models.Parent p = new com.dks.models.Parent();
            p.setUserId(users.getId());
            p.setCreateUserId(users.getId());
            p.setModifyUserId(users.getId());
            parentMapper.insert(p);

            //统计新用户注册奖励
            RewardUtil rewardUtil = new RewardUtil();
            rewardUtil.insertReward(users.getId(), 7);

            if (null == wechatUserInfo) {
                //写入微信用户表,
                final WechatUserInfo wechatUserInfoSave = new WechatUserInfo();
                wechatUserInfoSave.setOpenid(openid);
                wechatUserInfoSave.setNickname(nickname);
                wechatUserInfoSave.setUserId(users.getId());
                wechatUserInfoSave.setPrivilege("privilege");
                wechatUserInfoSave.setUnionid("unionid");
                wechatUserInfoSave.setCreateUserId(users.getId());
                wechatUserInfoSave.setModifyUserId(users.getId());
                wechatUserInfoMapper.insert(wechatUserInfoSave);
            }

            return getTokenResultModel(tel, userType);
        } else {
            //家长端有信息，判断微信是否绑定，未绑定进行绑定 该过程老用户倒入时使用
            if (null == wechatUserInfo) {
                //写入微信用户表,
                final WechatUserInfo wechatUserInfoSave = new WechatUserInfo();
                wechatUserInfoSave.setOpenid(openid);
                wechatUserInfoSave.setNickname(nickname);
                wechatUserInfoSave.setUserId(usersList.get(0).getId());
                wechatUserInfoSave.setPrivilege("privilege");
                wechatUserInfoSave.setUnionid("unionid");
                wechatUserInfoSave.setCreateUserId(usersList.get(0).getId());
                wechatUserInfoSave.setModifyUserId(usersList.get(0).getId());
                wechatUserInfoMapper.insert(wechatUserInfoSave);
            }
            //有信息返回token
            return getTokenResultModel(tel, userType);
        }

    }

    /**
     * @Author: Ah Nan
     * @Description: 老师手机号验证码登录
     * @Date: 10:42 2020/4/20
     * @Modificd By:
     * @Param: userType 用户类型 0 家长、1 老师
     * @return:
     * @throw: 请描述异常信息
     */
    @Override
    public ResultModel<Object> tcAppLogin(String tel, String code, String wechatCode) {
        //校验验证码是否和传过来的一致
        Object obj = redisTemplate.opsForValue().get(Commond.REDIS_KEY_PHONE_IDENTIFY_CODE + tel);
        if (null == obj || !code.equals(obj)) {
            return Result.makeResult(ResultInfo.EXCEPTION, "验证码已失效");
        }

        Map map = new HashMap();
        map.put("loginName", tel);
        map.put("userType", 1);
        map.put("recStatus", 0);
        List<Users> usersList = usersMapper.getByMapList(map);

        //老师不存在
        if (null == usersList || usersList.size() == 0) {
            //老师不存在联系web端处理
            return Result.makeResult(ResultInfo.ERR_DATA_STRUCTURE, "老师信息不存在请联系管理员新增信息");
        }

        String tokenStr = "";
        //校验code
        try {
            tokenStr = QSUnirest.unirestGetBase("https://api.weixin.qq.com/sns/jscode2session?appid=" + Commond.TEACHER_APP_ID + "&secret=" + Commond.TEACHER_APP_SECRET + "&js_code=" + wechatCode + "&grant_type=authorization_code");
        } catch (Exception e) {
            e.printStackTrace();
            logger.info("登录接口校验code异常：  " + tel);
        }

        final com.alibaba.fastjson.JSONObject tokenJo = com.alibaba.fastjson.JSONObject.parseObject(tokenStr);
        final String access_token = tokenJo.getString("access_token");
        final String openid = tokenJo.getString("openid");

        //根据openid查询微信用户信息
        final WechatUserInfo wechatUserInfo = wechatUserInfoMapper.selectByOpenId(openid);

        if (null == wechatUserInfo) {
            //写入微信用户表,
            final WechatUserInfo wechatUserInfoSave = new WechatUserInfo();
            wechatUserInfoSave.setOpenid(openid);
            wechatUserInfoSave.setNickname(usersList.get(0).getNickname());
            wechatUserInfoSave.setUserId(usersList.get(0).getId());
            wechatUserInfoSave.setPrivilege("privilege");
            wechatUserInfoSave.setUnionid("unionid");
            wechatUserInfoSave.setCreateUserId(usersList.get(0).getId());
            wechatUserInfoSave.setModifyUserId(usersList.get(0).getId());
            wechatUserInfoMapper.insert(wechatUserInfoSave);
        }

        return getTokenResultModel(tel, 1);
    }

    /**
     * @Author: Ah Nan
     * @Description: 微信登录绑定用户信息
     * @Date: 14:05 2020/4/21
     * @Modificd By:
     * @Param: wechatCode 微信开放平台code
     * @return:
     * @throw: 请描述异常信息
     */
    @Override
    @Transactional
    public ResultModel<Object> bindingWechatUser(UserDto userDto) {

        userDto.setUserType(0);
        int row = usersMapper.insert(userDto);
        if (row == 1) {
            WechatUserInfo wechatUserInfo = new WechatUserInfo();
            wechatUserInfo.setOpenid(userDto.getOpenid());
            wechatUserInfo.setNickname(userDto.getNickname());
            wechatUserInfo.setUserId(userDto.getId());
            wechatUserInfo.setCreateUserId(userDto.getId());
            wechatUserInfo.setModifyUserId(userDto.getId());
            wechatUserInfoMapper.updateByOpenId(wechatUserInfo);
        }
        return Result.makeResult(ResultInfo.SUCCESS, row);
    }


    /**
     * @Author: Ah Nan
     * @Description: 微信登录
     * @Date: 14:05 2020/4/21
     * @Modificd By:
     * @Param: wechatCode 微信开放平台code
     * @return:
     * @throw: 请描述异常信息
     */
    @Override
    @Transactional
    public ResultModel<Object> wechatLogin(String wechatCode) throws Exception {
        logger.info("微信授权后台登录：wechatCode=" + wechatCode + ",userType：" + 1);
        final String tokenStr;
        //通过code获取access_token和openid
        tokenStr = QSUnirest.unirestGetBase("https://api.weixin.qq.com/sns/jscode2session?appid=" + Commond.PARENT_APP_ID + "&secret=" + Commond.PARENT_APP_SECRET + "&js_code=" + wechatCode + "&grant_type=authorization_code");

        final com.alibaba.fastjson.JSONObject tokenJo = com.alibaba.fastjson.JSONObject.parseObject(tokenStr);
        final String access_token = tokenJo.getString("access_token");
        final String openid = tokenJo.getString("openid");

        //根据微信用户openid查询用户
        final String loginName = wechatUserInfoMapper.getLoginNameByOpenid(openid);

        //根据openid查询微信用户信息
        final WechatUserInfo wechatUserInfo = wechatUserInfoMapper.selectByOpenId(openid);

//        if (wechatUserInfo == null) {
//            //此时微信绑定用户不存在 注册用户
//            //抛异常
//            logger.info("微信授权后台登录：wechatCode=" + wechatCode + "：动态生成用户信息并且注册");
//            final WechatUserInfo wechatUserInfoSave = new WechatUserInfo();
//            wechatUserInfoSave.setOpenid(openid);
//            wechatUserInfoSave.setPrivilege("privilege");
//            wechatUserInfoSave.setUnionid("unionid");
//            //默认值用户信息调取后在修改
//            wechatUserInfoSave.setCreateUserId(Long.valueOf(0));
//            wechatUserInfoSave.setModifyUserId(Long.valueOf(0));
//            final int i = wechatUserInfoMapper.insert(wechatUserInfoSave);
//            if (i != 1) {
//                //插入失败
//                throw new RuntimeException("保存微信用户信息失败");
//            }
//        }
        if (loginName != null && !"".equals(loginName)) {
            //此时用户存在返回token
            return getTokenResultModel(loginName, 0);
        } else {
            //返回NOT_REGISTER_WECHAT_CODE、openid、微信昵称
            final com.alibaba.fastjson.JSONObject retJo = new com.alibaba.fastjson.JSONObject();
            retJo.put("openid", openid);
            return Result.makeResult(ResultInfo.NOT_REGISTER_WECHAT_CODE, retJo);
        }
    }


    /**
     * @Author: Ah Nan
     * @Description: 获取手机号是否绑定过微信
     * @Date: 14:05 2020/4/21
     * @Modificd By:
     * @Param: tel 手机号
     * @return:
     * @throw: 请描述异常信息
     */
    @Override
    public ResultModel<Object> getWeChatBindByUser(String tel) {
        Map map = new HashMap();
        map.put("loginName", tel);
        map.put("recStatus", 0);
        Integer row = usersMapper.getWeChatBindByUser(map);

        return Result.makeResult(ResultInfo.SUCCESS, row);
    }

    /**
     * @Author: Ah Nan
     * @Description: 微信注册并登录
     * @Date: 14:05 2020/4/21
     * @Modificd By:
     * @Param: tel 用户手机号
     * @Param: randomNumParam 验证码
     * @Param: openid 微信开放平台id
     * @return:
     * @throw: 请描述异常信息
     */
    @Override
    @Transactional
    public ResultModel<Object> wechatRegisterLogin(String tel, String randomNumParam, String openid, Integer userType) throws BaseException {
        //校验短信验证码 根据手机号取出对象信息 从redis中取数
        Object obj = (String) redisTemplate.opsForValue().get(Commond.REDIS_KEY_PHONE_IDENTIFY_CODE + tel);

        if (null == obj || !randomNumParam.equals(obj)) {
            return Result.makeResult(ResultInfo.EXCEPTION, "验证码已失效");
        }

        //验证成功后就从redis中删掉
        redisTemplate.delete(Commond.REDIS_KEY_PHONE_IDENTIFY_CODE + tel);

        //根据openid查询百辐用户信息（是否存在），存在返回token，不存在就注册百辐用户
        String loginName = wechatUserInfoMapper.getLoginNameByOpenid(openid);

        if (loginName == null || loginName.isEmpty()) {
            //为空注册用户and绑定微信
            Users users = new Users();
            Date date = new Date();
            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
            users.setLoginName(tel);
            users.setUserType(userType);
            users.setNickname("qs" + sdf.format(date) + String.valueOf((int) (Math.random() * (9999 - 1000 + 1)) + 1000));
            users.setProfilePhotoUrl("https://bat100.oss-cn-qingdao.aliyuncs.com/head/7bdd0991806c.png");
            int row = usersMapper.insert(users);

            //用户插入成功，绑定微信userid
            if (row == 1) {
                WechatUserInfo wechatUserInfo = new WechatUserInfo();
                wechatUserInfo.setOpenid(openid);
                wechatUserInfo.setUserId(users.getId());
                wechatUserInfo.setNickname(users.getNickname());
                int rowWe = wechatUserInfoMapper.updateByOpenId(wechatUserInfo);

                if (rowWe == 1) {
                    //插入家长信息
                    com.dks.models.Parent p = new com.dks.models.Parent();
                    p.setUserId(users.getId());
                    p.setCreateUserId(users.getId());
                    p.setModifyUserId(users.getId());
                    parentMapper.insert(p);
                    //注册成功返回token
                    return getTokenResultModel(tel, userType);
                } else {
                    throw new BaseException(ResultInfo.SQ_EXCEPTION);
                }

            } else {
                throw new BaseException(ResultInfo.SQ_EXCEPTION);
            }

        } else {
            //不为空返回token
            return getTokenResultModel(tel, userType);
        }
    }

    /**
     * @Author: Ah Nan
     * @Description: 获取用户信息
     * @Date: 14:05 2020/4/21
     * @Modificd By:
     * @Param: loginName 手机号
     * @return: data 0：代表未绑定，1：代表已绑定
     * @throw: 请描述异常信息
     */
    @Override
    public ResultModel<Object> getUserInfo(Integer userId) {
        Map<String, Object> map = new HashMap<>();
        map.put("id", userId);
        map.put("recStatus", 0);
        UserInfoDto usersList = usersMapper.getInfoByMapList(map);
        return Result.makeResult(ResultInfo.SUCCESS, usersList);
    }


    /**
     * @Author: Ah Nan
     * @Description: 获取token唯一方法
     * @Date: 11:19 2020/4/20
     * @Modificd By:
     * @Param:
     * @return:
     * @throw: 请描述异常信息
     */
    public ResultModel<Object> getTokenResultModel(final String tel,
                                                   final Integer userType
    ) {

        //1000*60*60*24*30*3  token有效期3个月
        final String token = Jwts.builder()
                .setSubject(tel)
                .setExpiration(new Date(System.currentTimeMillis() + 7776000000L))
                .signWith(SignatureAlgorithm.HS512, "MyJwtSecret1AF600AB94AD4CE9ADD37E3B69E78B901AF4CACCAD5748B3945F626868F52DB7")
                .compact();

        //将token数据存入redis
        redisTemplate.opsForValue().set(Commond.REDIS_KEY_TABLE_USER_TOKEN + tel, token);
        //设置token的过期时间为90天
        redisTemplate.expire(Commond.REDIS_KEY_TABLE_USER_TOKEN + tel, 90, TimeUnit.DAYS);

        //拼装用户信息和token
        final com.alibaba.fastjson.JSONObject dataJo = new com.alibaba.fastjson.JSONObject();
        Map map = new HashMap();
        map.put("loginName", tel);
        map.put("recStatus", 0);
        if (userType == 0) {
            //家长
            List<ParentVo> usersList = usersMapper.getUserParentList(map);
            dataJo.put("loginName", tel);
            dataJo.put("userType", userType);
            dataJo.put("token", token);
            dataJo.put("nickname", usersList.get(0).getNickname());
            dataJo.put("profilePhotoUrl", usersList.get(0).getProfilePhotoUrl());
            dataJo.put("userId", usersList.get(0).getUserId());
            dataJo.put("parentId", usersList.get(0).getId());
            dataJo.put("parentGroupId", usersList.get(0).getParentGroupId());

        } else {
            //老师
            List<TeacherVo> teacherList = usersMapper.getTeacherParentList(map);
            dataJo.put("loginName", tel);
            dataJo.put("userType", userType);
            dataJo.put("token", token);
            dataJo.put("nickname", teacherList.get(0).getNickname());
            dataJo.put("profilePhotoUrl", teacherList.get(0).getProfilePhotoUrl());
            dataJo.put("userId", teacherList.get(0).getUserId());
            dataJo.put("teacherId", teacherList.get(0).getId());
            dataJo.put("teacherBeginTime", teacherList.get(0).getTeacherBeginTime());
            dataJo.put("university", teacherList.get(0).getUniversity());
        }
        //验证成功后删掉redis中的key
        redisTemplate.delete(Commond.REDIS_KEY_PHONE_IDENTIFY_CODE + tel);

        return Result.makeResult(ResultInfo.SUCCESS, dataJo);
    }
}
